using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using UwinEducation.API.Attributes;
using UwinEducation.Application.Common.Interfaces;
using Microsoft.Extensions.Logging;
using UwinEducation.Shared.Models;
using Newtonsoft.Json;
using System.Text;
using UwinEducation.Shared.Services;

namespace UwinEducation.API.Middleware;

/// <summary>
/// 权限验证中间件
/// </summary>
public class PermissionAuthorizationMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<PermissionAuthorizationMiddleware> _logger;

    public PermissionAuthorizationMiddleware(
        RequestDelegate next,
        ILogger<PermissionAuthorizationMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }

    public async Task InvokeAsync(
    HttpContext context,
    IPermissionService permissionService,
    ICurrentUserService currentUserService,
    ICacheService cacheService)

    {
        try
        {
            var endpoint = context.GetEndpoint();
            if (endpoint == null)
            {
                await _next(context);
                return;
            }

            // 检查是否需要授权
            var authorizeAttribute = endpoint.Metadata.GetMetadata<AuthorizeAttribute>();
            if (authorizeAttribute == null)
            {
                await _next(context);
                return;
            }

            // 检查是否已认证
            if (!currentUserService.IsAuthenticated)
            {
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                await context.Response.WriteAsJsonAsync(ApiResponse<object>.Error("未登录", 401));
                return;
            }
            // 验证当前token是否有效
            var currentToken = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
            var userId = currentUserService.UserId;

            if (!userId.HasValue)
            {
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                await context.Response.WriteAsJsonAsync(ApiResponse<object>.Error("Invalid token", 401));
                return;
            }

            var validToken = await cacheService.GetAsync<string>($"valid_token:{userId}");
            if (validToken != currentToken)
            {
                context.Response.StatusCode = StatusCodes.Status401Unauthorized;
                await context.Response.WriteAsJsonAsync(ApiResponse<object>.Error("Token is no longer valid", 401));
                return;
            }

            // 检查是否需要权限验证
            var requirePermission = endpoint.Metadata.GetMetadata<RequirePermissionAttribute>();
            if (requirePermission == null)
            {
                await _next(context);
                return;
            }

            // 验证权限
            var hasPermission = await permissionService.HasPermissionAsync(
                currentUserService.UserId.Value,
                requirePermission.PermissionCode);

            if (!hasPermission)
            {
                context.Response.StatusCode = StatusCodes.Status403Forbidden;
                await context.Response.WriteAsJsonAsync(ApiResponse<object>.Error("没有访问权限", 403));
                return;
            }

            await _next(context);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "权限验证过程中发生错误");
            throw;
        }
    }
    private async Task<string> FormatRequest(HttpRequest request)
    {
        var body = string.Empty;

        // 启用请求重用
        request.EnableBuffering();

        // 读取请求body
        using (var reader = new StreamReader(
            request.Body,
            encoding: Encoding.UTF8,
            detectEncodingFromByteOrderMarks: false,
            leaveOpen: true))
        {
            body = await reader.ReadToEndAsync();
            // 重置请求body位置
            request.Body.Position = 0;
        }

        return $"{request.Method} {request.Scheme}://{request.Host}{request.Path}{request.QueryString}\n" +
               $"Headers: {JsonConvert.SerializeObject(request.Headers)}\n" +
               $"Body: {body}";
    }
}